import java.awt.Color;
import java.awt.Graphics;
import java.awt.Point;
import java.util.Formatter;
import java.util.Map;

import com.speljohan.rsbot.bot.Bot;
import com.speljohan.rsbot.event.listeners.PaintListener;
import com.speljohan.rsbot.script.Calculations;
import com.speljohan.rsbot.script.Script;
import com.speljohan.rsbot.script.wrappers.RSArea;
import com.speljohan.rsbot.script.wrappers.RSNPC;
import com.speljohan.rsbot.script.wrappers.RSTile;

public class ChocolateLover extends Script implements PaintListener {

	private double averageRunTime;
	private long startTime;
	private String status="Starting Script";
	private int chocolateDustBanked=0;
	private int errorCount;
	private long startRunTime;
	private int completeRuns;

	private final int MAXERROR=10;
	
	private RSArea bankArea = new RSArea(3427, 2890, 3, 4);
	private RSTile[] bankBooths = {new RSTile(3426,2893),new RSTile(3426,2891)};
	
	private RSArea stallArea = new RSArea(3429,2912,6,3);
	private int rokuhID = 3045;
	private int dust = 1975;
	private int chocolate = 1973;
	private int mandp = 233;
	private int coins = 995;
	
	private RSArea pathArea1 = new RSArea(3431,2901,4,11);
	private RSArea pathArea2 = new RSArea(3431,2892,4,9);
	
	private int phase = 0;
	private final int ATBANK =1;
	private final int ATSTALL=2;
	private final int ATPATH1=3;
	private final int ATPATH2=4;
	private final int BUYING=5;
	private final int BANKING=6;
	private final int GRINDING=7;

	public ChocolateLover() {
		setParameter("author", "Jankal");
		setParameter("version", 1.0);
		setParameter("name", "Chocolate Lover");
		setParameter("category", "Money");
	}

	public String getScriptDescription() {
		String html="<html><head></head><body>";
		html+="<h2><b>"+getName()+" v"+getVersion()+"</b></h2><br/>";
		html+="<b>Author:</b> "+getAuthor()+"<br/>";
		html+="<b>Description:</b> Personal Use Only</body></html>";
		return html;
	}

	public boolean onStart(Map<String, String> args) {
		bankArea.createWeightedTileArray(new int[]{1,1,2,1},new int[]{2,1,1});
		stallArea.createWeightedTileArray(new int[]{1,1,1},new int[]{1,1,1,1,1,1});
		pathArea1.createWeightedTileArray(new int[]{1,1,1,2,2,2,1,2,1,1,1},new int[]{2,1,1,1,});
		pathArea2.createWeightedTileArray(new int[]{1,1,1,2,2,1,1,1,1},new int[]{2,1,1,1,});
		setRun(true);
		startTime=System.currentTimeMillis();
		startRunTime=System.currentTimeMillis();
		return true;
	}

	public int loop() {
		if(getInventoryCount(coins)<20){
			log("Out of Money");
			return -1;
		}
		if(errorCount>MAXERROR){log("ERRORED OUT at phase: "+phase);return -1;}
		switch(phase){
			case ATBANK:
				status="Walking";
				if(isInventoryFull()){
					if(openBank()){changePhase(BANKING);errorCount=0;}
					else {
						errorCount++;
						if(errorCount>(MAXERROR/2))changePhase(ATPATH2);
					}
				}else if(runTo(pathArea2))changePhase(ATPATH2);else errorCount++;
				break;
			case ATSTALL:
				status="Walking";
				if(!isInventoryFull()){
					if(openStall())changePhase(BUYING);
					else {
						errorCount++;
						if(errorCount>(MAXERROR/2))changePhase(ATPATH1);
					}
				}else if(inventoryContains(dust)){
					if(runTo(pathArea1))changePhase(ATPATH1);else errorCount++;
				}else changePhase(GRINDING);
				break;
			case ATPATH1:
				status="Walking";
				if(isInventoryFull()){
					if(runTo(pathArea2))changePhase(ATPATH2);else errorCount++;
				}else{
					if(runTo(stallArea))changePhase(ATSTALL);else errorCount++;
				}break;
			case ATPATH2:
				status="Walking";
				if(isInventoryFull()){
					if(runTo(bankArea))changePhase(ATBANK);else errorCount++;
				}else{
					if(runTo(pathArea1))changePhase(ATPATH1);else errorCount++;
				}break;
			case GRINDING:
				status="Grinding";
				if(inventoryContains(chocolate)){
					if(!grind())errorCount++;
				}else changePhase(ATSTALL);
				break;
			case BUYING:
				status="Buying";
				if(isInventoryFull()){
					changePhase(ATSTALL);
				}else{
					if(!buy())errorCount++;
				}break;
			case BANKING:
				status="Banking";
				if(isInventoryFull()){
					if(!bank())errorCount++;
				}else changePhase(ATBANK);
				break;
			case 0:if(!setPhase()){log("We are Lost EXIT");return -1;}
		}
		return random(100,150);
	}

	private void changePhase(int nphase){
		phase=nphase;
		errorCount=0;
	}

	private boolean bank() {
		bank.depositAllExcept(mandp,coins);
		wait(random(50,100));
		if(inventoryContains(dust))return false;
		chocolateDustBanked+=26;
		completeRuns++;
		long runTime = System.currentTimeMillis() - startRunTime;
		averageRunTime = ((completeRuns - 1) * averageRunTime + runTime)/completeRuns;
		startRunTime=System.currentTimeMillis();
		return true;
	}

	private boolean buy() {
		try {
			clickMouse(random(110, 126), random(100, 113), false);
			atMenu("Buy X");
			wait(random(900, 1100));
			if (getInterface(752, 5).getText().equals("*")) {
				Bot.getInputManager().sendKeys("26", false);
				if (getInterface(137, 51).getText().contains("26*")) {
					Bot.getInputManager().holdKey(8, random(2000, 3000));
					return false;
				}
				Bot.getInputManager().sendKeys("", true);
				wait(random(800, 1200));
				if (inventoryContains(chocolate)){
					while(getInterface(620).isValid()){
						clickMouse(random(480,489),random(28,45),true);
						wait(random(300,500));
						if(!getInterface(620).isValid())return true;
					}
					return true;
				}
				Bot.getInputManager().holdKey(27, random(100, 300));
			}
			return false;
		} catch (Exception e) {
			return false;
		}
	}

	private boolean grind() {
		if(inventoryContains(dust)){wait(random(800,1500));return true;}
		int[] items = getInventoryArray();
		int mandpIndex;
		for(mandpIndex=0;mandpIndex<items.length;mandpIndex++){
			if(items[mandpIndex]==mandp)break;
		}
		int chocolateIndex;
		for(chocolateIndex=0;chocolateIndex<items.length;chocolateIndex++){
			if(items[chocolateIndex]==chocolate)break;
		}
		if((chocolateIndex>=items.length)||(mandpIndex>=items.length))return false;
		Point p = getInventoryItemPoint(mandpIndex);
		clickMouse(p.x,p.y,5,5,true);
		p = getInventoryItemPoint(chocolateIndex);
		clickMouse(p.x,p.y,5,5,true);
		wait(random(800,1000));
		if(getInterface(513).isValid()){
			clickMouse(253,417,7,7,false);
			atMenu("Make All");
			wait(random(1000,1500));
			if(!getInterface(513).isValid()){
				return true;
			}
		}
		return false;
	}

	private boolean openStall() {
		if(isMenuOpen())clearMenu();
		if(getInterface(620).isValid())return true;
		RSNPC r = getNearestNPCByID(rokuhID);
		if(r==null){wait(random(1000,1500));return false;}
		Point p = Calculations.tileToScreen(r.getLocation(), 20);
		if((p.x==-1)||(p.y==-1)){wait(random(1000,1500));return false;}
		moveMouse(p.x,p.y,3,3);
		if(getInterface(620).isValid())return true;
		p = Calculations.tileToScreen(r.getLocation(), 20);
		if((p.x==-1)||(p.y==-1)){wait(random(1000,1500));return false;}
		moveMouse(p.x,p.y,3,3);
		if(getInterface(620).isValid())return true;
		clickMouse(false);
		atMenu("Trade");
		wait(random(700,1500));
		if(getInterface(620).isValid())return true;
		return false;
	}

	private void clearMenu() {
		Point po = getMouseLocation();
		Point p=po;
		p.x+=random(120,140);
		if(random(1,2)==2)p.y+=random(1,140);
		else p.y-=random(1,140);
		if(p.x>761)p.x=761;
		if(p.y<1)p.y=1;
		if(p.y>500)p.y=500;
		moveMouse(4,p.x,p.y,5,5);
		wait(random(50,100));
		moveMouse(4,po.x,po.y,5,5);
	}

	private boolean openBank() {
		if(bank.isOpen())return true;
		if(isMenuOpen())clearMenu();
		RSTile bankTile = bankBooths[random(0,bankBooths.length)];
		Point p = Calculations.tileToScreen(bankTile, 0);
		if((p.x==-1)||(p.y==-1)){wait(random(1000,1500));return false;}
		moveMouse(p.x,p.y,3,3);
		if(bank.isOpen())return true;
		p = Calculations.tileToScreen(bankTile, 0);
		if((p.x==-1)||(p.y==-1)){wait(random(1000,1500));return false;}
		moveMouse(p.x,p.y,3,3);
		if(bank.isOpen())return true;
		clickMouse(false);
		wait(random(50,100));
		atMenu("Use-quickly");
		wait(random(1000,1500));
		if(bank.isOpen())return true;
		return false;
	}

	private boolean runTo(RSArea to){
		RSTile loc = to.getRandomTile();
		Point p =Calculations.worldToMinimap(loc.getX(), loc.getY());
		if((p.x==-1)||(p.y==-1)){wait(random(1000,1500));return false;}
		moveMouse(p.x,p.y,0,0);
		p =Calculations.worldToMinimap(loc.getX(), loc.getY());
		if((p.x==-1)||(p.y==-1)){wait(random(1000,1500));return false;}
		moveMouse(p.x,p.y,0,0);
		clickMouse(true);
		wait(random(800,2000));
		return true;
	}
	
	private boolean setPhase() {
		RSTile[] locs = {bankArea.getRandomTile(),
						 stallArea.getRandomTile(),
						 pathArea1.getRandomTile(),
						 pathArea2.getRandomTile()};
		int dist = distanceTo(locs[0]);
		phase=1;
		int tempDist;
		for(int i=1;i<locs.length;i++){
			tempDist=distanceTo(locs[i]);
			if(tempDist<dist){
				dist=tempDist;
				phase=i+1;
			}
		}
		if(dist>10)return false;
		return true;
	}
	
	@Override
	public void onRepaint(Graphics g) {
		if (!isLoggedIn() || g == null)return;
		int x = 7;
		int y = 230;
		double elapsedTime = System.currentTimeMillis() - startTime;
		Formatter f = new Formatter();
		Formatter f2 = new Formatter();
		String time = f.format("%d:%02d:%02d",
				new Integer((int) elapsedTime / 1000 / 60 / 60),
				new Integer((int) ((elapsedTime / 1000 / 60) % 60)),
				new Integer((int) (elapsedTime / 1000) % 60)).toString();
		g.setColor(new Color(110, 110, 110, 170));
		g.fill3DRect(x - 2, y, 197, 108, true);
		g.setColor(Color.white);
		g.drawString("Status: " + status, x, y += 15);
		g.drawString("Run Time: " + time, x, y += 15);
		g.drawString("Banked Dust: " + chocolateDustBanked, x, y += 15);
		g.drawString("Estimated Profit: "+chocolateDustBanked*(101-20), x, y+=15);
		g.drawString("Estimated Profit Per Hour: "+new Long((long) ((chocolateDustBanked*(101-20))/(elapsedTime/1000/60/60))).toString(), x, y+=15);
		g.drawString("# Dust Per Hour: "+new Long((long) ((chocolateDustBanked)/(elapsedTime/1000/60/60))).toString(), x, y+=15);
		g.drawString(f2.format("Average Run Time: %.3f sec",averageRunTime/1000).toString(), x, y += 15);
	}
}